import 'dart:convert';
import 'dart:math' hide log;
import 'dart:typed_data';
import 'package:pointycastle/asymmetric/api.dart';

import 'package:encrypt/encrypt.dart';

import '../exts/app_ext.dart';
import '../exts/plugins_ext.dart';

class DecodeUtil {
  final _MAX_LENTH = 117;
  final _MAX_DECODE_LENTH = 128;
  final encodeKey = '-----BEGIN PUBLIC KEY-----\n'
      'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfXfMzgg4m5RRLg2vcrYBFN4sBhE1VtW1sBkXxC5wtCRaOZv0kudk9CIQfU6c+eEaaZKUnygxHWdSqdwURCE0IKgLcolXF+RHmu/rl977FfjRg9pAkBg5z05PfHDqWqkIsqX0iRaSP31BUZOgtwafbiBv2dBvRBMdq03ty4q8OQQIDAQAB\n'
      '-----END PUBLIC KEY-----';
  final decodeKey = '-----BEGIN PRIVATE KEY-----\n'
      'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAITfvlC8+Nr+vz3DnhuCWW41ax8PG+rCiXt/f4XjRMlj9ZC2AuMMbtHLsTMLhCrhgHt1MxdcoYtqvQfxu4AVOh6pZrxMr2AiyNpw8SecmM3m0YWYNc7tnUB6/vlLyQduikD4qaxNiB5FcUiRpiRoLpz7rT6UV+/zDh+ibgvZRLDRAgMBAAECgYB7/mMV6tJ7YkBKPdK8Lw6PZq/5Att1XmZ3ZYo2Adg96tbMXN0izYZYprFMRhHnBhokm0C7K0jg1hFiaXUkWCqr83H+Y+DZ7js9NDhApPYAELQDIu288/nz34mjU/wnIGWP6WK5PCd1QjR8ltFay1TDLecdavHHjWGfHOMYnY5/dQJBAOZ4ICB+VrXMwR8KUR3r420YAHPwQDQKDetMHwgYHtFUH/k3CtKzPrltx103OhQcKyfrkoPj8SREZZISaBEQL6cCQQCTl+pjOSMud4hFTvfTnkGx9EZT3dBAv31ZfzHCu4g41FxRLyJLY6iKce069IhMjC2gfoLtwDLM/dKzRAuw9+rHAkAd9/zlfMg1t7xdFvBZXbUjGH3mlZUjrzMEJ8/ZM5m+SpwlwfyMTXaYkifcfTP2LXuHI2DX+an/t00l43LY1Sv9AkAEgQ5WGNhKArvV4aMOgjXfCGVdCdfhIfbhVFBgcPinQ1PN5nJVeqUaFH/43J2MOHrr+vBj8Qmb1+MmNV1l+SrhAkArJjCosjMI32RT3GmC6+gwxADR9Ib53yDHwRoMeO34dgK3hj3+e66Jhpcht3AjXBVs7bF9xzXcePpxxCka9cEv\n'
      '-----END PRIVATE KEY-----';

  final pwdKey='agropal2024!@#*.';

  RSAKeyParser? _parser;

  static final DecodeUtil _instance = DecodeUtil._init();

  factory DecodeUtil() => _instance;

  DecodeUtil._init() {
    _parser = RSAKeyParser();
  }

  ///解密请求返回数据
  Future<String> decodeResponse(Map<String, dynamic> response,
      {bool isEncode = true}) async {
    // showLog('解密前--$response');
    if (!isEncode) {
      return formatJson(response);
    }
    try {
      String key = response['encrypted']; //加密的key
      String content = response['requestData']; //加密的内容
      var decodeKey = await _decodeKey(key); //解密之后的key值

      var decodeContent = await _aesDecode(content, decodeKey);
      // showLog('解密后--$response');
      return decodeContent;
    } catch (e) {
      loggerMsg('解密错误：$e');
      return response.toString();
    }
  }

  ///加密请求参数
  Future<Map<String, dynamic>> encodeRequest(Map<String, dynamic>? params,
      {isEncode = true}) async {
    params ??= {};
    if (!isEncode) {
      return params;
    }

    var key = _getRandomString(16);
    var value = jsonEncode(params);
    try {
      var keyEncrypt = await _encodeKey(key);
      var valueEnctype = await _aesContent(value, key);
      var requestData = {'encrypted': keyEncrypt, 'requestData': valueEnctype};
      return requestData;
    } catch (e) {
      return params;
    }
  }

  ///AES 解密value值
  Future<String> _aesDecode(String content, String keyDe) async {
    try {
      final encrypter =
          Encrypter(AES(Key(utf8.encoder.convert(keyDe)), mode: AESMode.ecb));
      return encrypter.decrypt64(content, iv: IV.fromLength(_MAX_DECODE_LENTH));
    } catch (e) {
      return content;
    }
  }

  ///RSA 解密返回参数key值
  Future<String> _decodeKey(String content) async {
    return utf8.decode(await _decodeByPrivate(content));
  }

  ///RSA私钥解密
  Future<List<int>> _decodeByPrivate(String content) async {
    try {
      // String key = await rootBundle.loadString('assets/files/private.pem');
      var publicKey = RSAKeyParser().parse(decodeKey) as RSAPrivateKey;
      final encrypter = Encrypter(RSA(privateKey: publicKey));

      var sourceBytes = base64.decode(content);
      var inputLen = sourceBytes.length;
      var maxLen = _MAX_DECODE_LENTH;
      var totalBytes = List<int>.empty(growable: true);
      for (var i = 0; i < inputLen; i += maxLen) {
        var endLen = inputLen - i;
        Uint8List item;
        if (endLen > maxLen) {
          item = sourceBytes.sublist(i, i + maxLen);
        } else {
          item = sourceBytes.sublist(i, i + endLen);
        }
        totalBytes.addAll(encrypter.decryptBytes(Encrypted(item)));
      }
      return totalBytes;
    } catch (e) {
      return utf8.encode(content);
    }
  }

  ///AES 加密value值
  Future<String> _aesContent(String content, String key) async {
    try {
      final encrypt =
          Encrypter(AES(Key(utf8.encoder.convert(key)), mode: AESMode.ecb));
      return encrypt.encrypt(content, iv: IV.fromUtf8(content)).base64;
    } catch (e) {
      return content;
    }
  }

  ///RSA 加密请求参数key值
  Future<String> _encodeKey(String content) async {
    return const Base64Encoder().convert(await _encodeByPublic(content));
  }

  ///RSA公钥加密
  Future<List<int>> _encodeByPublic(String content) async {
    try {
      // String key = await rootBundle.loadString('assets/files/public.pem');
      var parameter = _parser!.parse(encodeKey) as RSAPublicKey;
      var encrypt = Encrypter(RSA(publicKey: parameter));
      var contentByte = utf8.encode(content);
      var inputLenth = contentByte.length;
      var outByte = List<int>.empty(growable: true);
      for (var i = 0; i < inputLenth; i += _MAX_LENTH) {
        // 还剩多少字节长度
        var endLen = inputLenth - i;
        List<int> item;
        if (endLen > _MAX_LENTH) {
          item = contentByte.sublist(i, i + _MAX_LENTH);
        } else {
          item = contentByte.sublist(i, i + endLen);
        }
        // loggerMsg(item);
        // 加密后的对象转换成字节数组再存放到容器
        outByte.addAll(encrypt.encryptBytes(item).bytes);
      }
      return outByte;
    } catch (e) {
      return utf8.encode(content);
    }
  }

  String _getRandomString(int lenth) {
    var base = 'abcdefghijklmnopqrstuvwxyz0123456789';
    var buffer = StringBuffer();
    var random = Random();
    for (var i = 0; i < lenth; i++) {
      buffer.write(base[random.nextInt(base.length)]);
    }
    return buffer.toString();
  }

  ///加密登录密码
  String encryptionPwd(String src) {
    try {
      var aes=AES(Key(utf8.encoder.convert(pwdKey)), mode: AESMode.ecb);
      var s=aes.encrypt(utf8.encoder.convert(src));
      showLog(Base64Encoder().convert(s.bytes));
      final encrypt =
      Encrypter(AES(Key(utf8.encoder.convert(pwdKey)), mode: AESMode.ecb));
      return encrypt.encrypt(src).base64;
    } catch (e) {
      return src;
    }
  }
}
